﻿// -----------------------------------------------------------------------
// <copyright company="www.3WayWebdesign.de">
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions:
// 
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
// </copyright>
// 
// <author>Michael Morbach</author>
// <email>Michael@3waywebdesign.de</email>
// <web>http://www.3waywebdesign.de</web>
// ----------------------------------------------------------------------

using System.Collections.Generic;
using System.Linq;
using Microsoft.Practices.Prism.Events;
using Microsoft.Practices.Prism.Regions;
using Microsoft.Practices.Unity;
using Tww.MAF.MAFInfrastructure.Abstract;
using Tww.MAF.MAFInfrastructure.Events.Composite;
using Tww.MAF.MAFInfrastructure.Interfaces.Services;
using Tww.MAF.MAFInfrastructure.Interfaces.ViewModels;
using Tww.MAF.MAFInfrastructure.Interfaces.Views;
using Tww.MAF.MAFInfrastructure.Models.UI.Menu;

namespace Tww.MAF.MAFMenuBarModule.Services
{
    #region Imports

    

    #endregion

    public class MenuBarService : ModuleServiceBase, IMenuBarService
    {
        #region Private Fields

        #endregion

        #region Ctors

        public MenuBarService(IEventAggregator eventAggregator, IUnityContainer unityContainer,
            IRegionManager regionManager)
            : base(eventAggregator, unityContainer, regionManager)
        {
        }

        #endregion

        #region Public Methods

        /// <summary>
        /// Activatiert das Modul in der angegebenen Region.
        /// </summary>
        /// <param name="regionName">Name der Region.</param>
        public override void ActivateModuleInRegion(string regionName)
        {
            RegionManager.RegisterViewWithRegion(regionName, typeof (IMenuBarView));
            ActiveInRegion = regionName;
        }

        /// <summary>
        /// Feuert eine Nachricht an alle Abonnenten des Ereignisses, dass ein neuer Menüeintrag angeklickt wurde
        /// </summary>
        /// <param name="entry">Menüeintrag der angeklickt wurde</param>
        public void PublishMenuItemClicked(IMenuTreeEntry entry)
        {
            var menuItemSelectedEvent = EventAggregator.GetEvent<MenuEntryClicked>();
            menuItemSelectedEvent.Publish(entry);
        }

        /// <summary>
        ///     Fügt einen neuen Eintrag in den Stamm des Baummenüs mit ein
        /// </summary>
        /// <param name="entry">Neuer Menüeintrag</param>
        public void AddMenuEntry(IMenuTreeEntry entry)
        {
            var menuViewModel = UnityContainer.Resolve<IMenuBarViewModel>();

            if (menuViewModel != null)
            {
                menuViewModel.AddTabItem(entry);
            }
        }

        /// <summary>
        ///     Entfernt einen vorhandenen Wurzelmenüeintrag
        /// </summary>
        /// <param name="existingEntryName">Name eines bestehenden Menüeintrages</param>
        public void RemoveMenuEntry(string existingEntryName)
        {
            var menuViewModel = UnityContainer.Resolve<IMenuBarViewModel>();

            if (menuViewModel != null)
            {
                // Durchlaufe alle Nodes bis ein Treffer gefunden wurde
                IMenuTreeEntry existingNode = SearchNode(existingEntryName, menuViewModel.MenuItems);

                if (existingNode == null)
                {
                    throw new KeyNotFoundException(
                        string.Format("Es konnte kein 'MenuEntry' mit dem Namen {0} gefunden werden", existingEntryName));
                }
                menuViewModel.RemoveTabItem(existingNode);
                existingNode.Disband();
            }
        }

        /// <summary>
        ///     Fügt einen neuen Eintrag als Kindelement eines bestehenden Eintrags hinzu. Wenn mehrere Einträge mit gleichem Namen
        ///     existieren so wird immer der erste gefundene Treffer als Vaterelement genutzt
        /// </summary>
        /// <param name="entry">Neue Menüeintrag</param>
        /// <param name="existingEntryName">Name eines bestehenden Menüeintrages</param>
        public void AttachMenuEntry(IMenuTreeEntry entry, string existingEntryName)
        {
            var menuViewModel = UnityContainer.Resolve<IMenuBarViewModel>();

            if (menuViewModel != null)
            {
                // Durchlaufe alle Nodes bis ein Treffer gefunden wurde
                IMenuTreeEntry existingNode = SearchNode(existingEntryName, menuViewModel.MenuItems);

                if (existingNode == null)
                {
                    throw new KeyNotFoundException(
                        string.Format("Es konnte kein 'MenuEntry' mit dem Namen {0} gefunden werden", existingEntryName));
                }
                entry.AttachTo(existingNode);
            }
        }

        /// <summary>
        ///     Gibt an ob ein Eintrag mit dem angegebenen Namen im Menübaum existiert
        /// </summary>
        /// <param name="entryName">Name nach dem gesucht werden soll</param>
        /// <returns>True -> Eintrag gefunden, False -> Kein Eintrag gefunden</returns>
        public bool Contains(string entryName)
        {
            var menuViewModel = UnityContainer.Resolve<IMenuBarViewModel>();

            // Durchlaufe alle Nodes bis ein Treffer gefunden wurde
            return (menuViewModel != null) && SearchNode(entryName, menuViewModel.MenuItems) != null;
        }

        /// <summary>
        ///     Gibt alle Wurzeleinträge aus der Baumstruktur zurück
        /// </summary>
        /// <returns>Liste mit Wurzeleinträge</returns>
        public List<IMenuTreeEntry> GetRootEntries()
        {
            var menuViewModel = UnityContainer.Resolve<IMenuBarViewModel>();

            return (menuViewModel != null)
                ? menuViewModel.MenuItems.Where(u => u.Parent == null).ToList()
                : new List<IMenuTreeEntry>();
        }

        /// <summary>
        ///     Leert die Baumstruktur
        /// </summary>
        public void ClearTree()
        {
            var menuViewModel = UnityContainer.Resolve<IMenuBarViewModel>();

            if (menuViewModel != null)
            {
                menuViewModel.ClearTree();
            }
        }

        /// <summary>
        ///     Searches a tree of nodes for a specific name
        /// </summary>
        /// <param name="existingMenuItemName">Node to search for</param>
        /// <param name="collectionToSearch">Tree to search in</param>
        /// <returns>Null or a Node</returns>
        private IMenuTreeEntry SearchNode(string existingMenuItemName, IEnumerable<IMenuTreeEntry> collectionToSearch)
        {
            var menuTreeEntries = collectionToSearch as IList<IMenuTreeEntry> ?? collectionToSearch.ToList();
            IMenuTreeEntry result = menuTreeEntries.FirstOrDefault(z => z.Title.ToLower() == existingMenuItemName.ToLower());

            if (result == null)
            {
                var innerNodes = menuTreeEntries.SelectMany(z => z.Children).ToList();

                if (innerNodes.Any())
                {
                    return SearchNode(existingMenuItemName, innerNodes);
                }
            }

            return result;
        }

        #endregion
    }
}